package encryption

import (
	"awesomeProject1/pkg/e"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"errors"
	"github.com/simplechain-org/client/log"
	"github.com/tjfoc/gmsm/sm2"
	"github.com/tjfoc/gmsm/sm3"
	"github.com/tjfoc/gmsm/sm4"
	"github.com/tjfoc/gmsm/x509"
	"strings"
)

const BlockSize = 16
const C1C3C2 = 0
const C1C2C3 = 1

var IV = make([]byte, BlockSize)

func SetIV(iv []byte) error {
	if len(iv) != BlockSize {
		return errors.New("SM4: invalid iv size")
	}
	IV = iv
	return nil
}

//sm4 对称加密
func Sm4Encrypt(plainText string, sm4Key string) (cipherText string, code int, errInfo string) {
	plainTextBytes := []byte(plainText)
	key := []byte(sm4Key)

	if len(key) != 16 && len(key) != 24 && len(key) != 32 {
		code = e.Sm4ErrKeyLengthError
		return
	}

	iv := []byte("0000000000000000")
	err := SetIV(iv) //设置SM4算法实现的IV值,不设置则使用默认值
	if err != nil {
		log.Error("设置SM4算法实现的IV值错误，使用默认值", "err", "err", err.Error())
	}
	ecbMsg, err := sm4.Sm4Ecb(key, plainTextBytes, true) //sm4Ecb模式pksc7填充加密
	if err != nil {
		code = e.Sm4ErrorFromEncryption
		return
	}

	//base64编码
	cipherText = base64.StdEncoding.EncodeToString(ecbMsg)

	return cipherText, e.Ok, ""
}

//sm4 对称解密
func Sm4Decrypt(cipherText string, sm4Key string) (plainText string, code int, errInfo string) {
	if len(strings.TrimSpace(cipherText)) < 1 {
		code = e.Sm4ErrCipherTextIsEmpty
		return
	}

	//解码
	cipherTextBytes, err2 := base64.StdEncoding.DecodeString(cipherText)
	if err2 != nil {
		code = e.ErrorFromDecryption2
		errInfo = err2.Error()
		return
	}

	key := []byte(sm4Key)
	if len(key) != 16 && len(key) != 24 && len(key) != 32 {
		code = e.Sm4ErrKeyLengthError
		return
	}

	iv := []byte("0000000000000000")
	err := SetIV(iv) //设置SM4算法实现的IV值,不设置则使用默认值
	if err != nil {
		log.Error("设置SM4算法实现的IV值错误，使用默认值", "err", "err", err.Error())
	}

	ecbDec, err := sm4.Sm4Ecb(key, cipherTextBytes, false) //sm4Ecb模式pkcs7填充解密
	if err != nil {
		code = e.Sm4ErrorFromDecryption
		errInfo = err.Error()
		return
	}

	plainText = string(ecbDec)
	return plainText, e.Ok, ""
}

//sm2 非对称加密
func Sm2Encrypt(plainText string, sm2PublicKey string) (cipherText string, code int, errInfo string) {

	if len(strings.TrimSpace(plainText)) < 1 {
		code = e.Sm2ErrOriginallyTextIsEmpty
		return
	}
	if len(plainText) > 100000 {
		code = e.Sm2ErrTextTooMach
		return
	}

	pub, err := x509.ReadPublicKeyFromPem([]byte(sm2PublicKey))
	if err != nil {
		code = e.Sm2PubKeyReadErr
		errInfo = err.Error()
		return
	}

	//cipherBytes, err := pub.EncryptAsn1([]byte(plainText), rand.Reader)          //sm2加密
	cipherBytes, err := sm2.Encrypt(pub, []byte(plainText), rand.Reader, C1C3C2) //sm2加密
	if err != nil {
		code = e.Sm2ErrorFromEncryption
		errInfo = err.Error()
		return
	}

	//编码
	cipherText = base64.StdEncoding.EncodeToString(cipherBytes)

	return cipherText, e.Ok, ""
}

//sm2 非对称解密
func Sm2Decrypt(cipherText string, sm2privateKey string) (plainText string, code int, errInfo string) {
	if len(strings.TrimSpace(cipherText)) < 1 {
		code = e.Sm4ErrCipherTextIsEmpty
		return

	}
	if len(sm2privateKey) < 160 {
		code = e.Sm2PrivateKeyAtLeast256Bit
		return
	}
	if len(cipherText) > 100000 {
		code = e.Sm2ErrTextTooMach
		return
	}

	priv, err := x509.ReadPrivateKeyFromPem([]byte(sm2privateKey), nil)
	if err != nil {
		code = e.Sm2PrivateKeyReadErr
		errInfo = err.Error()
		return
	}

	//解码
	cipherBytes, err2 := base64.StdEncoding.DecodeString(cipherText)
	if err2 != nil {
		code = e.ErrorFromDecryption2
		errInfo = err2.Error()
		return
	}

	//plainBytes, err := priv.DecryptAsn1(cipherBytes) //sm2解密
	plainBytes, err := sm2.Decrypt(priv, cipherBytes, C1C3C2) //sm2解密
	if err != nil {
		code = e.Sm2ErrorFromDecryption
		errInfo = err.Error()
		return
	}

	plainText = string(plainBytes)
	return plainText, e.Ok, ""
}

//sm2 国密签名
func Sm2Sign(originText string, sm2privateKey string) (sign string, code int, errInfo string) {
	if len(sm2privateKey) < 160 {
		code = e.Sm2PrivateKeyAtLeast256Bit
		return
	}
	if len(originText) > 100000 {
		code = e.Sm2ErrTextTooMach
		return
	}

	priv, err := x509.ReadPrivateKeyFromPem([]byte(sm2privateKey), nil)
	if err != nil {
		code = e.Sm2PrivateKeyReadErr
		errInfo = err.Error()
		return
	}

	signature, err := priv.Sign(rand.Reader, []byte(originText), nil) //sm2签名
	if err != nil {
		code = e.Sm2ErrSignFailed
		errInfo = err.Error()
		return
	}

	sign = base64.StdEncoding.EncodeToString(signature)
	return sign, e.Ok, ""
}

//sm2 国密验签
func Sm2VerifySign(originText string, sm2PublicKey string, signature string) (
	verified bool, code int, errInfo string) {

	if len(sm2PublicKey) < 120 {
		code = e.Sm2PubKeyAtLeast256Bit
		return
	}
	if len(originText) > 100000 {
		code = e.Sm2ErrTextTooMach
		return
	}

	pub, err := x509.ReadPublicKeyFromPem([]byte(sm2PublicKey))
	if err != nil {
		code = e.Sm2PubKeyReadErr
		errInfo = err.Error()
		return
	}

	//解码
	signBytes, err2 := base64.StdEncoding.DecodeString(signature)
	if err2 != nil {
		code = e.ErrorFromDecryption2
		return
	}

	verified = pub.Verify([]byte(originText), signBytes) //sm2验签
	return verified, e.Ok, ""
}

//sm3 国密hash散列算法
func Sm3CheckSum(originText string) (sum string) {
	h := sm3.New()
	h.Write([]byte(originText))
	sumBytes := h.Sum(nil)
	sum = hex.EncodeToString(sumBytes)
	return sum
}
